/****************************************************************************
 *  _____       ______  _____
 * |_   _|     |  ____|/ ____|
 *   | |  _ __ | |__  | (___    Institute of Embedded Systems
 *   | | | '_ \|  __|  \___ \   Zürcher Hochschule für Angewandte
 *  _| |_| | | | |____ ____) |  Wissenschaften
 * |_____|_| |_|______|_____/   8401 Winterthur, Switzerland
 *
 ****************************************************************************
 *
 * @version $Rev: 204 $
 * @author  $Author: bacr $
 * @date    $Date: 2013-12-20 16:54:25 +0100 (ven., 20 déc. 2013) $
 *
 ***************************************************************************/

#ifndef __NET_ADDRESS_H__
#define __NET_ADDRESS_H__

#include "lwip/def.h"

#define MAC_ADDRESS_LEN         6
#define IPV4_ADDRESS_LEN        4
#define IPV6_ADDRESS_LEN        16
#define IPV6_ADDRESS_HW_LEN     8
#define IPV6_ADDRESS_WW_LEN     4
#define IPV6_ADDRESS_DW_LEN     2

/* see ETH_FRAME_LEN in '/usr/include/linux/if_ether.h' */
#define ETH_MAX_FRAME_SIZE      1600                    /**< Max. bytes in frame without preamble, SFD but with FCS (=CRC) */

typedef struct mac_address_t    mac_address_t;
typedef struct ipv4_address_t   ipv4_address_t;
typedef struct ipv6_address_t   ipv6_address_t;

/** MAC address structure */
struct mac_address_t {
    uint8_t             addr[MAC_ADDRESS_LEN];          /**< byte-wise 48-bit MAC address */
};

/** IPv4 address structure */
struct ipv4_address_t {
    union {
        uint8_t         addr[IPV4_ADDRESS_LEN];         /**< byte-wise 32-bit IPv4 address */
        uint32_t        addr32;                         /**< 32-bit (word) IPv4 address, caution with byte-order! */
    };
};

/** IPv6 address structure */
struct ipv6_address_t {
    union {
        uint8_t         addr[IPV6_ADDRESS_LEN];         /**< byte-wise 128-bit IPv6 address */
        uint16_t        addr16[IPV6_ADDRESS_HW_LEN];    /**< 16-bit-wise (half-word) IPv6 address, caution with byte-order! */
        uint32_t        addr32[IPV6_ADDRESS_WW_LEN];    /**< 32-bit-wise (word) IPv6 address, caution with byte-order! */
        uint64_t        addr64[IPV6_ADDRESS_DW_LEN];    /**< 64-bit-wise (double-word) IPv6 address, caution with byte-order! */
    };
};

/**
 * Compares two MAC addresses
 *
 * @param   a               reference to a MAC address
 * @param   b               reference to a MAC address
 * @return                  true when MAC addresses match, false otherwise
 */
static inline bool
mac_address_compare(mac_address_t *a, mac_address_t *b)
{
    uint8_t idx;

    for (idx = 0; idx < MAC_ADDRESS_LEN; idx++) {
        if (a->addr[idx] != b->addr[idx]) {
            return false;
        }
    }

    return true;
}

/**
 * Compares two IPv4 addresses
 *
 * @param   a               reference to a IPv4 address
 * @param   b               reference to a IPv4 address
 * @return                  true when IPv4 addresses match, false otherwise
 */
static inline bool
ipv4_address_compare(ipv4_address_t *a, ipv4_address_t *b)
{
    return (a->addr32 == b->addr32) ? true : false;
}

/**
 * Compares two IPv6 addresses
 *
 * @param   a               reference to a IPv6 address
 * @param   b               reference to a IPv6 address
 * @return                  true when IPv6 addresses match, false otherwise
 */
static inline bool
ipv6_address_compare(ipv6_address_t *a, ipv6_address_t *b)
{
    uint8_t idx;

    for (idx = 0; idx < IPV6_ADDRESS_WW_LEN; idx++) {
        /* compare 32-bit numbers: when not-equal, a mismatch has been found => !success */
        if (a->addr32[idx] != b->addr32[idx]) {
            return false;
        }
    }

    return true;
}

#endif

